﻿Public Class Lvl_Data_Stations

    '测站集合
    Public LevelStations As List(Of Lvl_Data_Station)
    Private mCurrentStationIndex As Integer

    ''' <summary>
    ''' 当前测站索引
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Property CurrentStationIndex() As Integer
        Get
            Return mCurrentStationIndex
        End Get
        Set(ByVal value As Integer)
            mCurrentStationIndex = value
        End Set
    End Property

    ''' <summary>
    ''' 测站数
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    ReadOnly Property StationCount() As Integer
        Get
            Return LevelStations.Count
        End Get
    End Property

    ''' <summary>
    '''  初始化内存变量
    ''' </summary>
    ''' <remarks></remarks>
    Sub New()
        LevelStations = New List(Of Lvl_Data_Station)
        LevelStations.Add(New Lvl_Data_Station)
        mCurrentStationIndex = 0
    End Sub

    ''' <summary>
    ''' 增加新空测站
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function AddNew() As Lvl_Data_Station
        Dim vStn As Lvl_Data_Station = LastStation()
        If vStn.BackPoint.ValidPoint Then
            '新增测站
            LevelStations.Add(New Lvl_Data_Station)
        Else
            '新测站，直接返回
        End If
        mCurrentStationIndex = LevelStations.Count - 1
        Return LevelStations(mCurrentStationIndex)
    End Function

    ''' <summary>
    ''' 获取或设置当前测站
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property CurrentStation() As Lvl_Data_Station
        Get
            Return LevelStations.Item(mCurrentStationIndex)
        End Get
        Set(ByVal value As Lvl_Data_Station)
            LevelStations(mCurrentStationIndex) = value
        End Set
    End Property

    ''' <summary>
    ''' 下一站
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function NextStation() As Lvl_Data_Station
        If mCurrentStationIndex < LevelStations.Count - 1 Then
            mCurrentStationIndex += 1
        Else
            If LevelStations(LevelStations.Count - 1).BackPoint.ValidPoint Then
                LevelStations.Add(New Lvl_Data_Station)
                mCurrentStationIndex += 1
            End If
        End If
        Return LevelStations(mCurrentStationIndex)
    End Function

    ''' <summary>
    ''' 上一站
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function BeforeStation() As Lvl_Data_Station
        If mCurrentStationIndex > 0 Then mCurrentStationIndex -= 1
        Return LevelStations(mCurrentStationIndex)
    End Function

    ''' <summary>
    ''' 第一站
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function FirstStation() As Lvl_Data_Station
        mCurrentStationIndex = 0
        Return LevelStations(0)
    End Function

    ''' <summary>
    ''' 最后一站
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function LastStation() As Lvl_Data_Station
        mCurrentStationIndex = LevelStations.Count - 1
        Return LevelStations(LevelStations.Count - 1)
    End Function

    ''' <summary>
    ''' 以后视点点号查找测站
    ''' </summary>
    ''' <param name="BackPointName"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function FindStationByBackName(ByVal BackPointName As String) As Lvl_Data_Station
        For Each vP As Lvl_Data_Station In LevelStations
            If vP.BackPoint.Name = BackPointName Then
                Return vP
            End If
        Next
        Return Nothing
    End Function

    ''' <summary>
    ''' 返回测站的文本字符串
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Overrides Function ToString() As String
        Dim sTmp As String = ""
        For Each Stn As Lvl_Data_Station In LevelStations
            sTmp &= Stn.ToString & vbCrLf
            sTmp &= vbCrLf
        Next
        Return sTmp
    End Function



    ''' <summary>
    ''' 用文本初始化水准路线集
    ''' </summary>
    ''' <param name="sData"></param>
    ''' <remarks></remarks>
    ''' 
    Sub Read(ByVal sData As String)
        '初始化数据对象
        LevelStations.Clear()
        LevelStations.Add(New Lvl_Data_Station)
        mCurrentStationIndex = 0

        '有点号属性（Rb\Rf\Rz）出现的最小行号为起始行
        Dim pos As Integer = Math.Min(sData.IndexOf("Rb"), sData.IndexOf("Rf"))
        pos = Math.Min(pos, sData.IndexOf("Rz"))
        Dim StartPos As Long = Index_of_Start(sData, pos)

        '有点号属性（Rb\Rf\Rz）出现的最大行号为终止行
        pos = Math.Max(sData.LastIndexOf("Rb"), sData.LastIndexOf("Rf"))
        pos = Math.Max(pos, sData.LastIndexOf("Rz"))
        Dim EndPos As Long = Index_of_End(sData, pos)

        sData = sData.Substring(StartPos, EndPos - StartPos)
        Dim sLines() As String = sData.Split(vbCrLf)


        '记录最后换站的点号，用于判断是换站还是换水准路线
        Dim BeforeIsBlankLine As Boolean = False

        For Each sLine As String In sLines
            If sLine.Trim.Length = 0 Then
                If BeforeIsBlankLine Then
                Else
                    BeforeIsBlankLine = True
                    NextStation() '空行为测站换站
                End If

            Else
                BeforeIsBlankLine = False
                If IsReadLine(sLine) Then
                    Dim vP As New Lvl_Data_Point(sLine)
                    If vP.ValidPoint Then
                        Select Case vP.Prop
                            Case "Rb"
                                CurrentStation.BackPoint = vP

                            Case "Rf"
                                CurrentStation.ForePoint = vP

                            Case "Rz"
                                CurrentStation.MidPoint(vP.Name) = vP
                            Case Else
                        End Select
                    End If

                End If
            End If
        Next
    End Sub
    '已知行内任一位置后求该行起点
    Private Function Index_of_Start(ByRef sData As String, ByVal pos As Long) As Integer
        Do
            Dim tStr As String = sData.Substring(pos, 1)
            If Asc(tStr) = Asc(vbCrLf) Then
                pos += 1
                Exit Do
            Else
                If pos > 1 Then
                    pos -= 1
                Else
                    Exit Do
                End If
            End If
        Loop
        Return pos
    End Function
    '已知行内任一位置后求该行终点
    Private Function Index_of_End(ByRef sData As String, ByVal pos As Long) As Integer
        Dim TotalLength As Long = sData.Length
        Do
            Dim tStr As String = sData.Substring(pos, 1)
            If Asc(tStr) = Asc(vbCrLf) Then
                Exit Do
            Else
                If pos < TotalLength - 1 Then
                    pos += 1
                Else
                    Exit Do
                End If
            End If
        Loop
        Return pos
    End Function
    '有属性行，为观测记录
    Private Function IsReadLine(ByVal sLine As String) As Boolean
        If InStr(sLine, "Rb") > 0 OrElse InStr(sLine, "Rf") > 0 OrElse InStr(sLine, "Rz") > 0 Then
            Return True
        Else
            Return False
        End If
    End Function

    ''' <summary>
    ''' 以文本文件记录水准路线集
    ''' </summary>
    ''' <param name="FileName"></param>
    ''' <remarks></remarks>
    Sub Write(ByVal FileName As String)
        Dim sTmp As String = ToString()
        Try
            If PathAndFile.EximDictory(FileName) Then

                Dim FN As System.IO.StreamWriter = New IO.StreamWriter(FileName, True)
                FN.WriteLine(sTmp)
                FN.Close()

            End If
        Catch ex As Exception

        End Try
    End Sub

    ''' <summary>
    ''' 增加行号
    ''' </summary>
    ''' <remarks></remarks>
    Sub AddLineNumber()
        Dim StartIndex As Long = 1, EndIndex As Long = 0

        mCurrentStationIndex = 0
        Dim vStn As Lvl_Data_Station = LevelStations(0)

        vStn.LineNumber(StartIndex, EndIndex)
        Dim IndexTmp As Integer = mCurrentStationIndex
        Do
            StartIndex = EndIndex
            Dim vStnNext As Lvl_Data_Station = NextStation()
            '下一站还是同一站则结束
            If IndexTmp = mCurrentStationIndex Then
                Exit Do
            Else
                vStnNext.LineNumber(StartIndex, EndIndex)
                StartIndex = EndIndex
                IndexTmp = mCurrentStationIndex
            End If
        Loop

    End Sub

    ''' <summary>
    ''' 测站拼接
    ''' </summary>
    ''' <remarks></remarks>
    Sub Sort()

        Dim sWatchMsg As String = String.Empty

        '若最后站为无效站，则删除
        If Not (LevelStations(LevelStations.Count - 1).BackPoint.ValidPoint) Then
            LevelStations.RemoveAt(LevelStations.Count - 1)
        End If
        Dim HaveReSorted As Boolean

        Do
            For I As Integer = LevelStations.Count - 1 To 0 Step -1
                HaveReSorted = False
                '往前找一段连续的测站（从pos至i）
                Dim iPos As Integer = SearchNotContinuePosFromBack(I)
                Dim BkTmp As String = LevelStations(iPos).BackPoint.Name

                '往前找插入点
                For J As Integer = iPos - 1 To 0 Step -1
                    With LevelStations(J)
                        '前视点号或无前视测站的后视点号与之相同
                        If .ForePoint.Name = BkTmp OrElse _
                        ((Not .ForePoint.ValidPoint) And .BackPoint.Name = BkTmp) Then
                            '把连续测站移至此后
                            For K As Integer = I To iPos Step -1
                                Dim mstnTmp As Lvl_Data_Station = LevelStations(I)
                                LevelStations.RemoveAt(I)
                                LevelStations.Insert(J + 1, mstnTmp)
                            Next
                            HaveReSorted = True
                            Exit For
                        End If
                    End With
                Next
                sWatchMsg = ToString()
                If HaveReSorted Then Exit For

                '往后找插入点
                For J As Integer = I + 1 To LevelStations.Count - 1
                    With LevelStations(J)
                        '前视点号或无前视测站的后视点号与之相同
                        If .ForePoint.Name = BkTmp OrElse _
                        ((Not .ForePoint.ValidPoint) And .BackPoint.Name = BkTmp) Then
                            '把连续测站移至此后
                            For K As Integer = iPos To I
                                Dim mstnTmp As Lvl_Data_Station = LevelStations(iPos)
                                LevelStations.RemoveAt(iPos)
                                If J < LevelStations.Count - 1 Then
                                    LevelStations.Insert(J + 1, mstnTmp)
                                Else
                                    LevelStations.Add(mstnTmp)
                                End If

                            Next
                            HaveReSorted = True
                            Exit For
                        End If
                    End With

                Next
                sWatchMsg = ToString()
                If HaveReSorted Then Exit For

                I = iPos

            Next
            '只要移动过则，重新运行，直到从未移动测站
        Loop While (HaveReSorted)

    End Sub
    Private Function SearchNotContinuePosFromBack(ByVal Start As Integer) As Integer

        For I As Integer = Start To 1 Step -1
            Dim vStn2 As Lvl_Data_Station = LevelStations(I)
            Dim vStn1 As Lvl_Data_Station = LevelStations(I - 1)
            Dim Conitnues As Boolean = False


            If Not (vStn2.ForePoint.ValidPoint) Then

                '若本站没有前视，为只有后视与中视的测站，则只要与前站的后视、前视、中视任一点号匹配就行
                If vStn2.BackPoint.Name = vStn1.BackPoint.Name Or vStn2.BackPoint.Name = vStn1.ForePoint.Name Then
                    Conitnues = True
                Else
                    For J As Integer = 0 To vStn1.MidPointCount - 1
                        Dim vP As Lvl_Data_Point = vStn1.MidPoint(J)
                        If vStn2.BackPoint.Name = vP.Name Then
                            Conitnues = True
                            Exit For
                        End If
                    Next
                End If


            ElseIf Not (vStn1.ForePoint.ValidPoint) Then
                '若前站没有前视，为只有后视与中视的测站，则本站后视与前站后视同名也行
                If vStn2.BackPoint.Name = vStn1.BackPoint.Name Then
                    Conitnues = True
                End If



            ElseIf vStn2.BackPoint.Name = vStn1.ForePoint.Name Then
                Conitnues = True


            End If

            If Not Conitnues Then
                Return I
            End If

        Next
    End Function


    ''' <summary>
    ''' 返回点号集
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function PointNames() As String
        Dim sTmp As String = String.Empty
        For Each vStn As Lvl_Data_Station In LevelStations
            Dim ss As String = String.Empty
            ss = vStn.BackPoint.Name : If ss.Length > 0 Then sTmp &= ss & vbCrLf
            ss = vStn.ForePoint.Name : If ss.Length > 0 Then sTmp &= ss & vbCrLf
            For I As Integer = 0 To vStn.MidPointCount - 1
                ss = vStn.MidPoint(I).Name
                If ss.Length > 0 Then sTmp &= ss & vbCrLf
            Next
        Next
        Return sTmp
    End Function

    ''' <summary>
    '''点号拷贝 
    ''' </summary>
    ''' <param name="Stns"></param>
    ''' <remarks></remarks>
    Sub PointNameCopy(ByRef Stns As Lvl_Data_Stations)
        For Each Stn As Lvl_Data_Station In Stns.LevelStations
            Dim mStn As New Lvl_Data_Station
            mStn.BackPoint.Name = Stn.BackPoint.Name
            mStn.ForePoint.Name = Stn.ForePoint.Name

            For I As Integer = 0 To Stn.MidPointCount - 1
                Dim vP As New Lvl_Data_Point
                vP.Name = Stn.MidPoint(I).Name
                vP.Prop = "Rz"
                mStn.AddMidPoint(vP)
            Next

            With LevelStations(LevelStations.Count - 1)
                If .BackPoint.Name.Length > 0 Then
                    LevelStations.Add(mStn)
                Else
                    LevelStations(LevelStations.Count - 1) = mStn
                End If
            End With
        Next
        mCurrentStationIndex = 0
    End Sub

    ''' <summary>
    ''' 测站计算
    ''' </summary>
    ''' <param name="StartPointHeight"></param>
    ''' <remarks></remarks>
    Sub Calculate(ByVal StartPointHeight As Double)
        For i As Integer = 0 To LevelStations.Count - 1
            Dim vStn As Lvl_Data_Station = LevelStations.Item(i)
            vStn.Calculate(0)
        Next
    End Sub


End Class
